#include "ImageFilter.h"

int maskLaplacian[] = {
  -1, -1, -1,
  -1, 8, -1,
  -1, -1, -1, 1
};

int maskSobelX[] = {
  -1, 0, 1,
  -2, 0, 2,
  -1, 0, 1, 1
};

int maskSobelY[] = {
  1, 2, 1,
  0, 0, 0,
  -1, -2, -1, 1
};

int maskSobelXStrong[] = {
  -2, 0, 2,
  -4, 0, 4,
  -2, 0, 2, 1
};

int maskSobelYStrong[] = {
  2, 4, 2,
  0, 0, 0,
  -2, -4, -2, 1
};

int maskPrewittX[] = {
  -1, -1, -1,
  0, 0, 0,
  1, 1, 1, 1
};

int maskPrewittY[] = {
  1, 0, -1,
  1, 0, -1,
  1, 0, -1, 1
};

int maskGaussian[] = {
  1, 2, 1,
  2, 4, 2,
  1, 2, 1, 20
};

void filterImage(LPBYTE lpDest, LPBYTE lpSrc, int width, int height, int maskEachLength, int* mask1, int* mask2 /*= NULL*/) {
  LPBYTE lpTmp = lpDest;
  if (lpDest == lpSrc)
    lpTmp = new BYTE[width * height];

  int val, val2;
  for (int i = 1; i < height - 1; i++) {
    for (int j = 1; j < width - 1; j++) {
      val = val2 = 0;
      for (int m = 0; m < maskEachLength; m++) {
        for (int n = 0; n < maskEachLength; n++) {
          val += mask1[m * maskEachLength + n] * lpSrc[(i + m - 1) * width + (j + n - 1)];
          val /= mask1[SQUARE(maskEachLength)];
          if (mask2 != NULL) {
            val2 += mask2[m * maskEachLength + n] * lpSrc[(i + m - 1) * width + (j + n - 1)];
            val2 /= mask2[SQUARE(maskEachLength)];
          }
        }
      }
      lpTmp[i * width + j] = abs(val) + abs(val2);
    }
  }

  if (lpDest == lpSrc) {
    memcpy(lpDest, lpTmp, width * height * sizeof(BYTE));
    delete[] lpTmp;
  }
}

void filterImage(LPWORD lpDest, LPWORD lpSrc, int width, int height, int maskEachLength, int* mask1, int* mask2 /*= NULL*/) {
  LPWORD lpTmp = lpDest;
  if (lpDest == lpSrc)
    lpTmp = new WORD[width * height];

  int val, val2;
  for (int i = 1; i < height - 1; i++) {
    for (int j = 1; j < width - 1; j++) {
      val = val2 = 0;
      for (int m = 0; m < maskEachLength; m++) {
        for (int n = 0; n < maskEachLength; n++) {
          val += mask1[m * maskEachLength + n] * lpSrc[(i + m - 1) * width + (j + n - 1)];
          val /= mask1[SQUARE(maskEachLength)];
          if (mask2 != NULL){
            val2 += mask2[m * maskEachLength + n] * lpSrc[(i + m - 1) * width + (j + n - 1)];
            val2 /= mask2[SQUARE(maskEachLength)];
          }
        }
      }
      lpTmp[i * width + j] = abs(val) + abs(val2);
    }
  }

  if (lpDest == lpSrc) {
    memcpy(lpDest, lpTmp, width * height * sizeof(WORD));
    delete[] lpTmp;
  }
}

/*
최소값 필터 (침식)
*/
void filterMin(LPBYTE lpDest, LPBYTE lpSrc, int width, int height, int fX /*= 1*/, int fY /*= 1*/) {
  LPBYTE lpTmp = lpDest;
  if (lpDest == lpSrc)
    lpTmp = new BYTE[width * height];

  BYTE minVal;
  for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
      minVal = lpSrc[i * width + j];

      for (int m = i - fY; m < i + fY; m++)
        for (int n = j - fX; n < j + fX; n++)
          if (m >= 0 && m < height && n >= 0 && n < width)
            if (minVal > lpSrc[m * width + n])
              minVal = lpSrc[m * width + n];
      lpTmp[i * width + j] = minVal;
    }
  }

  if (lpDest == lpSrc) {
    memcpy(lpDest, lpTmp, width * height * sizeof(BYTE));
    delete[] lpTmp;
  }
}

void filterMin(LPWORD lpDest, LPWORD lpSrc, int width, int height, int fX /*= 1*/, int fY /*= 1*/) {
  LPWORD lpTmp = lpDest;
  if (lpDest == lpSrc)
    lpTmp = new WORD[width * height];

  WORD minVal;
  for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
      minVal = lpSrc[i * width + j];

      for (int m = i - fY; m < i + fY; m++)
        for (int n = j - fX; n < j + fX; n++)
          if (m >= 0 && m < height && n >= 0 && n < width)
            if (minVal > lpSrc[m * width + n])
              minVal = lpSrc[m * width + n];
      lpTmp[i * width + j] = minVal;
    }
  }

  if (lpDest == lpSrc) {
    memcpy(lpDest, lpTmp, width * height * sizeof(WORD));
    delete[] lpTmp;
  }
}

/*
최대값 필터 (팽창)
*/
void filterMax(LPBYTE lpDest, LPBYTE lpSrc, int width, int height, int fX /*= 1*/, int fY /*= 1*/) {
  LPBYTE lpTmp = lpDest;
  if (lpDest == lpSrc)
    lpTmp = new BYTE[width * height];

  BYTE maxVal;
  for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
      maxVal = lpSrc[i * width + j];

      for (int m = i - fY; m < i + fY; m++)
        for (int n = j - fX; n < j + fX; n++)
          if (m >= 0 && m < height && n >= 0 && n < width)
            if (maxVal < lpSrc[m * width + n])
              maxVal = lpSrc[m * width + n];
      lpTmp[i * width + j] = maxVal;
    }
  }

  if (lpDest == lpSrc) {
    memcpy(lpDest, lpTmp, width * height * sizeof(BYTE));
    delete[] lpTmp;
  }
}

void filterMax(LPWORD lpDest, LPWORD lpSrc, int width, int height, int fX /*= 1*/, int fY /*= 1*/) {
  LPWORD lpTmp = lpDest;
  if (lpDest == lpSrc)
    lpTmp = new WORD[width * height];

  WORD maxVal;
  for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
      maxVal = lpSrc[i * width + j];

      for (int m = i - fY; m < i + fY; m++)
        for (int n = j - fX; n < j + fX; n++)
          if (m >= 0 && m < height && n >= 0 && n < width)
            if (maxVal < lpSrc[m * width + n])
              maxVal = lpSrc[m * width + n];
      lpTmp[i * width + j] = maxVal;
    }
  }

  if (lpDest == lpSrc) {
    memcpy(lpDest, lpTmp, width * height * sizeof(WORD));
    delete[] lpTmp;
  }
}

void mopOpening(LPBYTE lpDest, LPBYTE lpSrc, int width, int height, int fX /*= 1*/, int fY /*= 1*/) {
  LPBYTE lpTmpBuf = new BYTE[width * height];
  filterMin(lpTmpBuf, lpSrc, width, height, fX, fY);
  filterMax(lpDest, lpTmpBuf, width, height, fX, fY);
  delete[] lpTmpBuf;
}

void mopOpening(LPWORD lpDest, LPWORD lpSrc, int width, int height, int fX /*= 1*/, int fY /*= 1*/) {
  LPWORD lpTmpBuf = new WORD[width * height];
  filterMin(lpTmpBuf, lpSrc, width, height, fX, fY);
  filterMax(lpDest, lpTmpBuf, width, height, fX, fY);
  delete[] lpTmpBuf;
}

void mopClosing(LPBYTE lpDest, LPBYTE lpSrc, int width, int height, int fX /*= 1*/, int fY /*= 1*/) {
  LPBYTE lpTmpBuf = new BYTE[width * height];
  filterMax(lpTmpBuf, lpSrc, width, height, fX, fY);
  filterMin(lpDest, lpTmpBuf, width, height, fX, fY);
  delete[] lpTmpBuf;
}

void mopClosing(LPWORD lpDest, LPWORD lpSrc, int width, int height, int fX /*= 1*/, int fY /*= 1*/) {
  LPWORD lpTmpBuf = new WORD[width * height];
  filterMax(lpTmpBuf, lpSrc, width, height, fX, fY);
  filterMin(lpDest, lpTmpBuf, width, height, fX, fY);
  delete[] lpTmpBuf;
}
